﻿using UnityEngine;
using System.Collections.Generic;

// 框架
public class Framework
{
    #region Instance
    static Framework ms_Instance;
    public static Framework Instance
    {
        get
        {
            if (ms_Instance == null)
            {
                ms_Instance = new Framework();
            }
            return ms_Instance;
        }
    }
    #endregion

    // 事件处理器委托
    public delegate void EventProc();
    public delegate void EventProcParam(EventBase evt);

    // 异步事件信息
    class AsynEventInfo
    {
        public EventBase evt;
        public float delay;
        public float start;
    }

    // 事件处理函数列表
    Dictionary<int, List<object>> m_events = new Dictionary<int, List<object>>();
    // 异步事件列表
    List<AsynEventInfo> m_asynEventInfos = new List<AsynEventInfo>();

    // 模块列表
    List<IModuleBase> m_modules = new List<IModuleBase>();
    List<IModuleBase> m_updateModules = new List<IModuleBase>();
    List<IModuleBase> m_fixedUpdateModules = new List<IModuleBase>();

    Framework()
    {

    }

    public void Shutdown()
    {
        m_events.Clear();
        m_asynEventInfos.Clear();

        m_updateModules.Clear();

        for (int i = 0; i < m_modules.Count; ++i)
        {
            IModuleBase module = m_modules[i];
            module.Dispose();
        }

        m_modules.Clear();
    }

    // 更新
    public void Update()
    {
        float dt = Time.unscaledDeltaTime;

        int count = m_updateModules.Count;
        for (int i = 0; i < count; ++i)
        {
            m_updateModules[i].Update(dt);
        }

        UpdateAsynEvents(dt);
    }

    public void FixedUpdate()
    {
        float dt = Time.fixedDeltaTime;
        int count = m_fixedUpdateModules.Count;
        for (int i = 0; i < count; ++i)
        {
            m_fixedUpdateModules[i].FixedUpdate(dt);
        }
    }

    public float CurrentTime { get { return Time.realtimeSinceStartup; } }

    public IModuleBase GetModule(string name)
    {
        for (int i = 0; i < m_modules.Count; ++i)
        {
            IModuleBase module = m_modules[i];
            if (string.Equals(module.GetName(), name))
            {
                return module;
            }
        }
        return null;
    }

    public T GetModule<T>() where T : IModuleBase
    {
        return (T)GetModule(typeof(T).FullName);
    }

    public bool AddModule(IModuleBase module)
    {
        for (int i = 0; i < m_modules.Count; ++i)
        {
            if (string.Equals(m_modules[i].GetName(), module.GetName()))
            {
                // 已存在
                return false;
            }
        }

        m_modules.Add(module);

        return true;
    }

    public bool RemoveModule(IModuleBase module)
    {
        RemoveUpdate(module);
        RemoveFixedUpdate(module);
        for (int i = 0; i < m_modules.Count; ++i)
        {
            if (string.Equals(m_modules[i].GetName(), module.GetName()))
            {
                m_modules.RemoveAt(i);
                break;
            }
        }

        return true;
    }

    public void InitModule()
    {
        for (int i = 0; i < m_modules.Count; ++i)
        {
            m_modules[i].Init();
        }
    }

    public bool AddUpdate(IModuleBase module)
    {
        for (int i = 0; i < m_updateModules.Count; ++i)
        {
            if (string.Equals(m_updateModules[i].GetName(), module.GetName()))
            {
                // 已存在
                return false;
            }
        }

        m_updateModules.Add(module);

        return true;
    }

    public bool RemoveUpdate(IModuleBase module)
    {
        for (int i = 0; i < m_updateModules.Count; ++i)
        {
            if (string.Equals(m_updateModules[i].GetName(), module.GetName()))
            {
                m_updateModules.RemoveAt(i);
                break;
            }
        }

        return true;
    }

    public bool AddFixedUpdate(IModuleBase module)
    {
        for (int i = 0; i < m_fixedUpdateModules.Count; ++i)
        {
            if (string.Equals(m_fixedUpdateModules[i].GetName(), module.GetName()))
            {
                // 已存在
                return false;
            }
        }

        m_fixedUpdateModules.Add(module);

        return true;
    }

    public bool RemoveFixedUpdate(IModuleBase module)
    {
        for (int i = 0; i < m_fixedUpdateModules.Count; ++i)
        {
            if (string.Equals(m_fixedUpdateModules[i].GetName(), module.GetName()))
            {
                m_fixedUpdateModules.RemoveAt(i);
                break;
            }
        }

        return true;
    }

    public bool HasEventProc(int id)
    {
        List<object> procs = null;
        if (!m_events.TryGetValue(id, out procs))
        {
            return false;
        }

        return procs.Count > 0;
    }

    // 事件
    bool AddEventProcInner(int id, object proc)
    {
        List<object> procs = null;

        if (!m_events.ContainsKey(id))
        {
            procs = new List<object>();
            m_events.Add(id, procs);
        }
        else
        {
            procs = m_events[id];
        }

        if (procs.Contains(proc))
        {
            return false;
        }

        procs.Add(proc);
        return true;
    }

    bool RemoveEventProcInner(int id, object proc)
    {
        if (!m_events.ContainsKey(id))
        {
            return false;
        }

        List<object> procs = m_events[id];
        return procs.Remove(proc);
    }

    public bool AddEventProc(object id, EventProcParam proc)
    {
        return AddEventProcInner((int)id, proc);
    }

    public bool RemoveEventProc(object id, EventProcParam proc)
    {
        return RemoveEventProcInner((int)id, proc);
    }

    public bool AddEventProc(object id, EventProc proc)
    {
        return AddEventProcInner((int)id, proc);
    }

    public bool RemoveEventProc(object id, EventProc proc)
    {
        return RemoveEventProcInner((int)id, proc);
    }

    public void SendEvent(EventBase evt)
    {
        int _id = (int)evt.ID;
        if (m_events.ContainsKey(_id))
        {
            List<object> procs = m_events[_id];

            for (int i = 0; i < procs.Count; ++i)
            {
                EventProcParam proc_1 = procs[i] as EventProcParam;
                if (proc_1 != null)
                {
                    proc_1(evt);
                }
                else
                {
                    EventProc proc_2 = procs[i] as EventProc;
                    if (proc_2 != null)
                    {
                        proc_2();
                    }
                }
            }
        }
    }

    public void PostEvent(EventBase evt, float delay = .0f)
    {
        AsynEventInfo info = new AsynEventInfo();
        info.evt = evt;
        info.delay = delay;
        info.start = CurrentTime;

        m_asynEventInfos.Add(info);
    }

    void UpdateAsynEvents(float dt)
    {
        int index = 0;
        AsynEventInfo info = null;

        while (index < m_asynEventInfos.Count)
        {
            info = m_asynEventInfos[index];
            if (CurrentTime - info.start >= info.delay)
            {
                m_asynEventInfos.RemoveAt(index);
                SendEvent(info.evt);
            }
            else
            {
                ++index;
            }
        }
    }
}